package insertionSort;

import shared.MyComparable;
import shared.MyStop;
import shared.SortInput;
import shared.SortInputVisitor;

/**
 * The {@link InputOutputProcessor} is an {@link InputProcessor} which knows its next processor.
 */
public class InputOutputProcessor<T extends Comparable<? super T>> extends InputProcessor<T>{

	private final InputProcessor<T> nextProcessor;

	public InputProcessor<T> getNextProcessor() {
		return nextProcessor;
	}

	/**
	 * Constructor of {@link InputOutputProcessor}
	 * @param nextProcessor is the next {@link InputProcessor} after this one.
	 */
	public InputOutputProcessor(final InputProcessor<T> nextProcessor) {
		this.nextProcessor = nextProcessor;
		new Thread(this).start();
	}
	
	@Override
	public void run() {
		while(!this.isDone()){
			final SortInput<T> input = this.getInputBuffer().get();
			input.accept(new SortInputVisitor<T>() {

				@Override
				public void visit(final MyComparable<T> myComparable) {
					InputOutputProcessor.this.getState().accept(new InputProcessorStateVisitor<T>() {

						@Override
						public void visit(final ReceivedInput<T> receivedInput) {
							if(myComparable.getComparable().compareTo(receivedInput.getInput()) < 0){
								InputOutputProcessor.this.getNextProcessor().getInputBuffer().put(myComparable);
							} else {
								InputOutputProcessor.this.getNextProcessor().getInputBuffer().put(new MyComparable<T>(receivedInput.getInput()));
								InputOutputProcessor.this.setState(new ReceivedInput<T>(myComparable.getComparable()));
							}
						}

						@Override
						public void visit(final ReceivedNoInput<T> receivedNoInput) {
							InputOutputProcessor.this.setState(new ReceivedInput<T>(myComparable.getComparable()));
						}
					});
				}

				@Override
				public void visit(final MyStop<T> myStop) {
					InputOutputProcessor.this.setResultFromState();
					InputOutputProcessor.this.getNextProcessor().getInputBuffer().put(myStop);
				}
			});
		}
	}
}